<template>
  <div class="box">
    <canvas ref="canvas"></canvas><br />
    <!-- <button @click="cameraAnimation()" class="button" v-if="!cameraButton">
      camera surround
    </button>
    <button @click="cameraAnimation()" class="button" v-else>
      stop surrounding
    </button>
    <button @click="runModel()" class="button" v-if="!modelButton">play</button>
    <button @click="runModel()" class="button" v-else>stop</button> -->
    <!-- <audio
      class="success"
      src="../../static/models/music/小鹿乱撞.mp3"
      :autoplay="false"
      :paused="musicPause"
      :muted="musicMute"
      :controls="false"
      ref="audio"
    ></audio> -->
    <!-- <button @click="reset()" class="button">reset</button> -->
    <el-progress
      type="circle"
      :percentage="progressPercent"
      class="progress"
      v-if="showProgress"
    ></el-progress>
    <div class="loadLog" v-if="showProgress">
      <p align="left" class="text-primary" id="progressLog"></p>
    </div>
  </div>
</template>

<script>
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { MMDAnimationHelper } from "three/examples/jsm/animation/MMDAnimationHelper";
import { MMDLoader } from "three/examples/jsm/loaders/MMDLoader";
import { FBXLoader } from "three/examples/jsm/loaders/FBXLoader.js";
import { OBJLoader } from "three/examples/jsm/loaders/OBJLoader.js";
import { MTLLoader } from "three/examples/jsm/loaders/MTLLoader.js";
import * as ammo from "../../../static/js/ammo";
export default {
  props: {
    projectInfo: Object,
  },
  data() {
    return {
      width: 0,
      height: 0,
      progressPercent: 0,
      currentLoadNum: 0,
      totalLoadNum: 8,
      showProgress: true,
      audioFile: "",
      renderer: null,
      camera: null,
      scene: null,
      cube: null,
      axesHelper: null,
      spotLight: null,
      control: null,
      model: null,
      MMDhelper: null,
      clock: null,
      Ammo: null,
      mmd: null,
      plane: null,
      cameraButton: false,
      modelButton: false,
      musicPause: false,
      musicMute: false,
      firstPlay: true,
      dataSever: this.$store.getters.dataSever,
    };
  },
  watch: {
    currentLoadNum(val) {
      this.progressPercent = (val / this.totalLoadNum) * 100;
      if (this.progressPercent == 100) {
        this.SLOG("全部加载完成，请稍等......");
        setTimeout(() => {
          this.showProgress = false;
          // this.scene.add(this.mmd);
          this.mmd.visible = true;
        }, 1000);
      }
    },
  },
  created() {
    // 获取屏幕宽高
    this.width = 1200;
    this.height = 680;
  },
  mounted() {
    // 挂在全局
    // const AMMO = require("three/examples/js/libs/ammo.wasm.js");
    // // const AMMO = require("../../static/js/ammo");
    // this.Ammo = new AMMO();
    // three挂在全局时间参数
    this.clock = new THREE.Clock();
    this.getRenderer();
    this.getCamera();
    this.getScene();
    // this.getCube();
    // this.getSpotLight(); // 聚光灯
    this.getPointLight();
    // this.getAmbientLight(); //环境光
    // this.getWorldBg(); // 世界背景
    this.getMMDModel();
    this.getPlane();
    this.getControl();
    this.animation();
  },
  methods: {
    // 获取渲染范围
    getRenderer() {
      let canvas = this.$refs.canvas;
      canvas.width = this.width;
      canvas.height = this.height;
      const render = new THREE.WebGLRenderer({ canvas });
      // render.gammaOutput = true // 调整渲染的颜色范围
      render.setSize(this.width, this.height);
      render.shadowMap.enabled = true; // 开启阴影模式
      this.renderer = render;
      this.currentLoadNum += 1;
      this.SLOG("render加载完成......");
    },
    // 获取相机
    getCamera() {
      const camera = new THREE.PerspectiveCamera(
        75,
        this.width / this.height,
        0.01,
        1000
      );
      camera.position.y = 5;
      camera.position.z = 20;
      camera.lookAt(0, 10, 0);
      this.camera = camera;
      this.currentLoadNum += 1;
      this.SLOG("camera加载完成......");
    },
    // 获取场景
    getScene() {
      const scene = new THREE.Scene();
      this.scene = scene;
      this.currentLoadNum += 1;
      this.SLOG("scene加载完成......");
    },
    // 获取盒子
    getCube() {
      //   const mesh = new THREE.Mesh(
      //     new THREE.BoxGeometry(1, 1, 1),
      //     new THREE.MeshLambertMaterial({ color: 0x00ff00 })
      //   );
      let geometry = new THREE.BoxGeometry(1, 1, 1, 2, 2, 2); // 长宽高
      // let meterial = new THREE.MeshNormalMaterial( { color: 0x00ff00 }) // 立方体材质 颜色，根据物体表面的法向量计算颜色
      let meterial = new THREE.MeshLambertMaterial({ color: 0x00ff00 }); // Lamber材质，支持反光，这种材质会考虑光照的影响，可以用来创建颜色暗淡、不光亮的物体
      let box = new THREE.Mesh(geometry, meterial); // 构造立方体 = 体积 + 材质
      box.position.set(-1, 0, 0);
      box.castShadow = true; // 开启阴影
      this.cube = box;
      this.scene.add(this.cube);
    },
    getSpotLight() {
      // 添加聚光灯
      let spotLight = new THREE.SpotLight(0xffffff);
      spotLight.position.set(-10, 10, 10); // 灯光位置
      spotLight.angle = Math.PI / 3; // 灯光角度
      spotLight.castShadow = true; // 开启阴影
      this.spotLight = spotLight;
      this.scene.add(this.spotLight);
      this.currentLoadNum += 1;
      this.SLOG("spotLight加载完成......");
    },
    getPointLight() {
      let pointLight = new THREE.PointLight(0xffffff, 1, 1000);
      pointLight.position.set(-10, 30, 10);
      // let pointLightHelper = new THREE.PointLightHelper(pointLight,1)
      // pointLight.castShadow = true; // 开启阴影
      this.scene.add(pointLight);
      this.currentLoadNum += 1;
      this.SLOG("pointLight加载完成......");
    },
    addBottomLeftLight() {
      let pointLight = new THREE.PointLight(0xffffff, 1, 1000);
      pointLight.position.set(-30, 0, 30);
      // let pointLightHelper = new THREE.PointLightHelper(pointLight,1)
      pointLight.castShadow = true; // 开启阴影
      this.scene.add(pointLight);
    },
    addBottomRightLight() {
      let pointLight = new THREE.PointLight(0xffffff, 1, 1000);
      pointLight.position.set(30, 0, -30);
      // let pointLightHelper = new THREE.PointLightHelper(pointLight,1)
      pointLight.castShadow = true; // 开启阴影
      this.scene.add(pointLight);
    },
    addBottomUpLight() {
      let pointLight = new THREE.PointLight(0xffffff, 1, 1000);
      pointLight.position.set(30, 20, -30);
      // let pointLightHelper = new THREE.PointLightHelper(pointLight,1)
      pointLight.castShadow = true; // 开启阴影
      this.scene.add(pointLight);
    },
    getAmbientLight() {
      let ambientLight = new THREE.AmbientLight(0xffffff, 0.7);
      // ambientLight.castShadow = true; // 开启阴影
      this.scene.add(ambientLight);
    },
    getPlane() {
      // 创建平面
      let planeGeo = new THREE.PlaneGeometry(1000, 1000, 100, 100); //创建平面
      let planeMat = new THREE.MeshLambertMaterial({
        //创建材料
        color: 0x666666,
        wireframe: false,
        // side: THREE.DoubleSide //看到两个面
      });
      let planeMesh = new THREE.Mesh(planeGeo, planeMat); //创建网格模型
      planeMesh.position.set(0, -10, 0); //设置平面的坐标
      planeMesh.rotation.x = -0.5 * Math.PI; //将平面绕X轴逆时针旋转90度
      planeMesh.receiveShadow = true; // 地板接收阴影
      this.plane = planeMesh;
      this.scene.add(planeMesh);
      this.currentLoadNum += 1;
      this.SLOG("plane加载完成......");
    },
    getControl() {
      //   let control = new THREE.OrbitControls(
      //     this.camera,
      //     this.renderder.domElement
      //   );
      let control = new OrbitControls(this.camera, this.renderer.domElement);
      this.control = control;
      this.currentLoadNum += 1;
      this.SLOG("control加载完成......");
    },
    getWorldBg() {
      const loader = new THREE.CubeTextureLoader();
      // 图片放图assets/images
      const bgTexture = loader
        .setPath("../../static/worldBg/")
        .load([
          "posx.jpg",
          "negx.jpg",
          "posy.jpg",
          "negy.jpg",
          "posz.jpg",
          "negz.jpg",
        ]);
      this.scene.background = bgTexture;
    },
    getMMDModel() {
      let fileUrl = this.projectInfo.url;
      let suffix = fileUrl.substring(fileUrl.lastIndexOf(".") + 1);
      if (suffix == "pmx") {
        this.MMDhelper = new MMDAnimationHelper();
        const gltfLoader = new MMDLoader();
        gltfLoader.load(this.dataSever + this.projectInfo.url, (mesh) => {
          mesh.position.set(0, -10, 0); // 调整位置
          mesh.castShadow = true; // 开启阴影
          // mesh.receiveShadow = true; // 地板接收阴影
          mesh.visible = false;
          this.mmd = mesh;
          this.scene.add(mesh);
          this.currentLoadNum += 2;
          this.SLOG("model加载完成......");
          this.SLOG("animation加载完成......");
        });
      } else if (suffix == "obj") {
        var loader = new OBJLoader(); //obj加载器
        let mtlLoader = new MTLLoader(); //材质文件加载器
        let mtlUrl =
          this.projectInfo.url.substring(
            0,
            this.projectInfo.url.lastIndexOf(".")
          ) + ".mtl";
        console.log(this.projectInfo.url);
        let that = this;
        mtlLoader.load(this.dataSever + mtlUrl, function (materials) {
          //   if (!materials) {
          //     console.log("no mtl file!");
          //   }
          let _that = that;
          //obj的模型会和MaterialCreator包含的材质对应起来
          loader.setMaterials(materials);
          loader.load(_that.dataSever + _that.projectInfo.url, function (obj) {
            //url自己定义
            //第一个表示模型路径，第二个表示完成导入后的回调函数
            //一般我们需要在这个回调函数中将导入的模型添加到场景中

            obj.traverse(function (child) {
              if (child instanceof THREE.Mesh) {
                obj.scale.set(0.04, 0.04, 0.04);
                obj.position.set(0, 0, 0);
                child.material.transparent = true; //材质透明
                if (child.geometry && !child.geometry.hasAttribute("normal")) {
                  child.geometry.computeVertexNormals();
                }
                //   child.castShadow = true;
                // child.receiveShadow = true;
              }
            });
            obj.compute;
            _that.mmd = obj;
            _that.scene.add(obj); //返回的组对象插入场景中
            _that.addBottomLeftLight();
            _that.addBottomRightLight();
            _that.addBottomUpLight();
            _that.currentLoadNum += 2;
            _that.SLOG("model加载完成......");
            _that.SLOG("animation加载完成......");
          });
        });
      } else if (suffix == "fbx") {
        var loader = new FBXLoader();
        let that = this;
        loader.load(this.dataSever + this.projectInfo.url, function (object) {
          object.traverse(function (child) {
            if (child.isMesh) {
              //   child.castShadow = true;
              //   child.receiveShadow = true;
            }
            if (child instanceof THREE.Mesh) {
              // obj.material.emissive=new THREE.Color(1,1,1);
              child.material.emissive = child.material.color;
              child.material.emissiveIntensity = 1;
              child.material.emissiveMap = child.material.map;
            }
          });
          object.rotation.y = Math.PI / 2;
          object.position.set(0, 0, 0);
          object.scale.set(0.04, 0.04, 0.04);
          that.scene.add(object);
          that.addBottomLeftLight();
          that.addBottomRightLight();
          //   that.plane.visible = false;
          that.mmd = object;
          that.currentLoadNum += 2;
          that.SLOG("model加载完成......");
          that.SLOG("animation加载完成......");
        });
      } else {
        this.$Message.error("模型创建失败，请检查上传的模型类型！");
      }
    },
    // 动画
    animation() {
      //   this.cube.rotation.x += 0.01;
      //   this.cube.rotation.y += 0.01;
      this.control.update(); // 动画渲染
      //   this.MMDhelper.update(this.clock.getDelta()); // mmd动画
      requestAnimationFrame(this.animation);
      this.renderer.render(this.scene, this.camera);
    },
    cameraAnimation() {
      this.cameraButton = !this.cameraButton;
      let uuids = [];
      uuids.push(this.mmd.uuid);
      uuids.push(this.plane.uuid);
      for (let i = 0; i < uuids.length; i++) {
        for (let j = 0; j < this.scene.children.length; j++) {
          if (uuids[i] == this.scene.children[j].uuid) {
            if (!this.cameraButton) {
              // close
              this.scene.children[j].position.set(0, -10, 0);
            } else {
              // open
              this.scene.children[j].position.set(0, 0, 0);
            }
          }
        }
      }
      if (!this.cameraButton) {
        //close
        this.MMDhelper.enabled.cameraAnimation = false;
      } else {
        this.MMDhelper.enabled.cameraAnimation = true;
      }
    },
    runModel() {
      this.modelButton = !this.modelButton;
      if (this.firstPlay && this.modelButton) {
        this.firstPlay = false;
        // 先音后动
        this.$refs["audio"].play();
        setTimeout(() => {
          this.MMDhelper.enabled.animation = true;
        }, 200);
      } else {
        if (!this.modelButton) {
          //close
          this.MMDhelper.enabled.animation = false;
          this.$refs["audio"].pause();
        } else {
          this.MMDhelper.enabled.animation = true;
          this.$refs["audio"].play();
        }
      }
    },
    reset() {
      // 复位
    },
    SLOG(str) {
      let loadingLog = document.getElementById("progressLog").innerHTML;
      if (str) {
        loadingLog += str + "</br>";
        document.getElementById("progressLog").innerHTML = loadingLog;
        return true;
      } else {
        loadingLog += "空LOG请找原因" + "</br>";
        document.getElementById("progressLog").innerHTML = loadingLog;
        return false;
      }
    },
  },
};
</script>

<style scoped>
.box {
  position: relative;
}
.button {
  margin-top: 10px;
  width: 120px;
  height: 40px;
}
.progress {
  position: absolute;
  /* margin: auto; */
  top: 30vh;
  left: 26vw;
}
.loadLog {
  position: absolute;
  /* margin: auto; */
  top: 50vh;
  left: 3vw;
}
.text-primary {
  /* font-size: 20px; */
  color: gray;
}
</style>